package util.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import util.IOUtils;
import util.interfaces.IMultipartFormData;

/**
 * 
 * @author 李东喜 2009-8-7
 */
public class MultipartFormDataImpl implements IMultipartFormData {

    private Logger log = Logger.getLogger(this.getClass());

    private List<FileItem> items;

    public MultipartFormDataImpl(HttpServletRequest request) {
        this.items = this.getFileItems(request);
    }

    /**
     * 
     * @param request
     * @return
     * @author 李东喜 2009-8-7
     */
    @SuppressWarnings("unchecked")
    public List<FileItem> getFileItems(HttpServletRequest request) {

        // 页面传过来的form的类型是不是: multipart/form-data
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);

        // 如果是, 则进行处理
        if (isMultipart) {
            try {
                FileItemFactory factory = new DiskFileItemFactory();
                ServletFileUpload upload = new ServletFileUpload(factory);

                // 获取页面所有的参数
                List<FileItem> items = upload.parseRequest(request);
                return items;

            } catch (FileUploadException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * 
     * @param name
     * @return
     * @author 李东喜 2009-8-7
     */
    public String getParameter(String name) {

        if (StringUtils.isNotEmpty(name) && null != this.items
                && this.items.size() > 0) {
            for (FileItem item : this.items) {
                if (item.isFormField() && name.equals(item.getFieldName())) {
                    return item.getString();
                }
            }
        }

        return null;
    }

    /**
     * 
     * @param name
     * @param encode
     * @return
     * @author 李东喜 2009-8-7
     */
    public String getParameter(String name, String encode) {

        String parameter = null;

        if (StringUtils.isNotEmpty(encode)) {
            if (StringUtils.isNotEmpty(name) && null != this.items
                    && this.items.size() > 0) {
                for (FileItem item : this.items) {
                    if (item.isFormField() && name.equals(item.getFieldName())) {
                        try {
                            parameter = item.getString(encode);
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                }
            }
        } else {
            return this.getParameter(name);
        }

        return parameter;
    }

    /**
     * 获取所有参数的值
     * @return
     * @author 李东喜
     * 2009-8-12
     */
    public String[] getParameters() {
        
        List<String> values = new ArrayList<String>();

        if (null != this.items && this.items.size() > 0) {
            for (FileItem item : this.items) {
                if (item.isFormField()) {
                    values.add(item.getString());
                }
            }
        }

        return values.toArray(new String[values.size()]);
    }
    
    /**
     * 获取指定参数的值
     * 
     * @param name
     * @return String[]
     * @author 李东喜 2009-8-7
     */
    public String[] getParameters(String name) {

        List<String> values = new ArrayList<String>();

        if (StringUtils.isNotEmpty(name) && null != this.items
                && this.items.size() > 0) {
            for (FileItem item : this.items) {
                if (item.isFormField() && name.equals(item.getFieldName())) {
                    values.add(item.getString());
                }
            }
        }

        return values.toArray(new String[values.size()]);
    }

    /**
     * 用指定编码获取指定参数的值
     * 
     * @param name
     * @param encode
     * @return String[]
     * @author 李东喜 2009-8-7
     */
    public String[] getParameters(String name, String encode) {

        List<String> values = new ArrayList<String>();

        if (StringUtils.isNotEmpty(encode)) {
            if (StringUtils.isNotEmpty(name) && null != this.items
                    && this.items.size() > 0) {
                for (FileItem item : this.items) {
                    if (item.isFormField() && name.equals(item.getFieldName())) {
                        try {
                            values.add(item.getString(encode));
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } else {
            return this.getParameters(name);
        }

        return values.toArray(new String[values.size()]);
    }

    /**
     * 
     * @param name
     * @return FileItem or null
     * @author 李东喜 2009-8-7
     */
    public FileItem getFile(String name) {

        if (StringUtils.isNotEmpty(name) && null != this.items
                && this.items.size() > 0) {
            for (FileItem item : this.items) {
                if (!item.isFormField() && name.equals(item.getFieldName()) && StringUtils.isNotEmpty(item.getName())) {
                    return item;
                }
            }
        }

        return null;
    }

    /**
     * 获取所有文件的封装对象
     * @return
     * @author 李东喜
     * 2009-8-12
     */
    public FileItem[] getFiles() {
        
        List<FileItem> items = new ArrayList<FileItem>();

        if (null != this.items && this.items.size() > 0) {
            for (FileItem item : this.items) {
                if (!item.isFormField() && StringUtils.isNotEmpty(item.getName())) {
                    items.add(item);
                }
            }
        }

        return items.toArray(new FileItem[items.size()]);
    }
    
    /**
     * 
     * @param name
     * @return FileItem[], never null
     * @author 李东喜 2009-8-7
     */
    public FileItem[] getFiles(String name) {

        List<FileItem> items = new ArrayList<FileItem>();

        if (StringUtils.isNotEmpty(name) && null != this.items
                && this.items.size() > 0) {
            for (FileItem item : this.items) {
                if (!item.isFormField() && name.equals(item.getFieldName()) && StringUtils.isNotEmpty(item.getName())) {
                    items.add(item);
                }
            }
        }

        return items.toArray(new FileItem[items.size()]);
    }

    /**
     * 
     * @param names
     * @return FileItem[], never null
     * @author 李东喜 2009-8-7
     */
    public FileItem[] getFiles(String[] names) {

        List<FileItem> files = new ArrayList<FileItem>();

        if (null != names && names.length > 0) {
            for (String name : names) {
                files.add(this.getFile(name));
            }
        }

        return files.toArray(new FileItem[files.size()]);
    }

    /**
     * 单个保存文件到指定的路径
     * 
     * @param name
     * @param filePath
     * @author 李东喜 2009-8-7
     */

    public void saveFile(String name, String filePath) {

        FileItem file = this.getFile(name);
        if (null == file) {
            System.out.println(String.format("找不到参数：[%1$s]", name));
        } else {
            File dir = new File(filePath);

            // 如果指定的文件夹的路径不是一个文件夹，则提示并且不保存文件
            if (!dir.isDirectory()) {
                System.out.println(String.format("路径不是一个文件夹：[%1$s]", filePath));
            } else {

                // 如果文件夹不存在则创建该文件夹
                if (!dir.exists()) {
                    System.out.println(String.format("文件夹不存在，创建该文件夹：[%1$s]",
                            dir.getAbsolutePath()));
                    dir.mkdirs();
                }

                // 从form里面获取到文件的完整路径
                String _filePath = file.getName();

                // 解析出文件名
                String fileName = _filePath.substring(_filePath
                        .lastIndexOf(File.separatorChar) + 1);

                // 目标文件
                File target = new File(dir.getAbsolutePath()
                        + File.separatorChar + fileName);

                // 如果文件不存在则创建 一个新的文件
                if (!target.exists()) {
                    System.out.println(String.format("目标文件不存在，创建该文件：[%1$s]",
                            target.getAbsolutePath()));
                    try {
                        target.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e);
                    }
                }

                InputStream is = null;
                OutputStream os = null;

                try {
                    is = file.getInputStream();
                    os = new FileOutputStream(target);

                    IOUtils.copy(is, os);

                    log.info(String.format("文件已经保存完毕：[%1$s]", target.getAbsolutePath()));
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                } finally {
                    IOUtils.close(os);
                    IOUtils.close(is);
                }
            }
        }
    }

    /**
     * 单个保存文件到指定的路径,并重命名
     * 
     * @param name
     * @param filePath
     *            文件路径
     * @param rename
     *            重命名
     * @author 李东喜 2009-8-7
     */
    public void saveFile(String name, String filePath, String rename) {

        FileItem file = this.getFile(name);
        if (null == file) {
            System.out.println(String.format("找不到参数：[%1$s]", name));
        } else {
            File dir = new File(filePath);

            // 如果指定的文件夹的路径不是一个文件夹，则提示并且不保存文件
            if (!dir.isDirectory()) {
                System.out.println(String.format("路径不是一个文件夹：[%1$s]", filePath));
            } else {

                // 如果文件夹不存在则创建该文件夹
                if (!dir.exists()) {
                    System.out.println(String.format("文件夹不存在，创建该文件夹：[%1$s]",
                            dir.getAbsolutePath()));
                    dir.mkdirs();
                }

                // 从form里面获取到文件的完整路径
                String _filePath = file.getName();
                
                // 文件后缀
                String suffix = _filePath.substring(_filePath.lastIndexOf('.'));
                
                // 重命名
                File target = new File(dir.getAbsolutePath()
                        + File.separatorChar + rename + suffix);

                // 如果文件不存在则创建 一个新的文件
                if (!target.exists()) {
                    System.out.println(String.format("目标文件不存在，创建该文件：[%1$s]",
                            target.getAbsolutePath()));
                    try {
                        target.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                InputStream is = null;
                OutputStream os = null;

                try {
                    is = file.getInputStream();
                    os = new FileOutputStream(target);

                    IOUtils.copy(is, os);

                    log.info(String.format("文件已经保存完毕：[%1$s]", target.getAbsolutePath()));
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                } finally {
                    IOUtils.close(os);
                    IOUtils.close(is);
                }
            }
        }
    }

    /**
     * 
     * @param name
     * @param filePath
     * @author 李东喜 2009-8-7
     */
    public void saveFiles(String name, String filePath) {
        
        FileItem[] files = this.getFiles(name);
        
        if (0 < files.length) {
            for (int i = 0; i < files.length; i++) {
                saveFile(files[i].getString(), filePath);
            }
        } else {
            log.info(String.format("获取不到指定参数的文件：[%1$s]", name));
        }
    }

    /**
     * @param names
     * @param filePath
     * @author 李东喜 2009-8-7
     */
    public void saveFiles(String[] names, String filePath) {
        
        FileItem[] files = getFiles(names);
        
        if (0 < files.length) {
            for (int i = 0; i < files.length; i++) {
                saveFile(files[i].getName(), filePath);
            }
        } else {
            log.info(String.format("获取不到指定参数的文件：%1$s", Arrays.toString(names)));
        }
    }

    /**
     * 
     * @param name
     * @param filePath
     * @param size
     * @throws RuntimeException
     * @author 李东喜 2009-8-11
     */
    public void saveFile(String name, String filePath, long size) {
        
        FileItem file = this.getFile(name);
        if (null != file) {
            if (file.getSize() <= size) {
                this.saveFile(name, filePath);
            } else {
                throw new RuntimeException(String.format("文件的大小不能大于%1$s：[%2$s(实际大小：%3$s)]", size, file.getName(), file.getSize()));
            }
        } else {
            log.info(String.format("获取不到指定参数的文件：%1$s", name));
        }
    }

    /**
     * 
     * @param name
     * @param filePath
     * @param rename
     * @param size
     * @throws RuntimeException
     * @author 李东喜 2009-8-11
     */
    public void saveFile(String name, String filePath, String rename, long size) {
        
        FileItem file = this.getFile(name);
        if (null != file) {
            if (file.getSize() <= size) {
                this.saveFile(name, filePath, rename);
            } else {
                throw new RuntimeException(String.format("文件的大小不能大于%1$s：[%2$s(实际大小：%3$s)]", size, file.getName(), file.getSize()));
            }
        } else {
            log.info(String.format("获取不到指定参数的文件：%1$s", name));
        }
    }

    /**
     * 
     * @param name
     * @param filePath
     * @param size
     * @throws RuntimeException
     * @author 李东喜 2009-8-11
     */
    public void saveFiles(String name, String filePath, long size) {
        
        FileItem[] files = this.getFiles(name);
        for (FileItem file : files) {
            if (file.getSize() <= size) {
                this.saveFile(name, filePath);
            } else {
                throw new RuntimeException(String.format("文件的大小不能大于%1$s：[%2$s(实际大小：%3$s)]", size, file.getName(), file.getSize()));
            }
        }
    }

    /**
     * 
     * @param names
     * @param filePath
     * @param size
     * @throws RuntimeException
     * @author 李东喜 2009-8-11
     */
    public void saveFiles(String[] names, String filePath, long size) {
        
        FileItem[] files = this.getFiles(names);
        for (FileItem file : files) {
            if (file.getSize() > size) {
                throw new RuntimeException(String.format("文件的大小不能大于%1$s：[%2$s(实际大小：%3$s)]", size, file.getName(), file.getSize()));
            }
        }
        this.saveFiles(names, filePath);
    }
}
